package vn.com.hung.notetaker.book.datamodels;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import javax.swing.table.AbstractTableModel;

import vn.com.hung.notetaker.datatypes.BookNoteRecord;
import vn.com.hung.notetaker.datatypes.BookTags;
import vn.com.hung.notetaker.utils.BookNoteLoader;
import vn.com.hung.notetaker.utils.SpecialChars;

import com.google.common.io.Closeables;
import com.google.common.io.Files;

public class BNTableModel extends AbstractTableModel{
    
    public static boolean DEBUG = false;
    
    private String modelFilePath = "";
    private BookNoteLoader loader;
    private String[] columnNames = {"Terms", "Contents", "Tags", "Misc"};
    
    private Vector<Vector<Object>> data = new Vector<Vector<Object>>();
    private Vector<Integer> highestCellIndex = new Vector<Integer>();
    
    public BNTableModel() {
        for (int i = 0; i < 50; i++) {
            Vector<Object> rowData = new Vector<Object>();
            rowData.add("");
            rowData.add("");
            rowData.add("");
            rowData.add("");
            data.add(rowData);
            highestCellIndex.add(0);
        }
    }
    
    public BNTableModel(String[] columnNames, Vector<Vector<Object>> data) {
        this.columnNames = columnNames;
        this.data = data;
        
    }
    @Override
    public int getColumnCount() {
        return columnNames.length;
    }

    @Override
    public int getRowCount() {
        return data.size();
    }
    @Override
    public String getColumnName(int col) {
        return columnNames[col];
      }
    @Override
    public Object getValueAt(int row, int col) {
        
        return data.get(row).get(col);
    }
    
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public Class getColumnClass(int c) {
        return getValueAt(0, c).getClass();
      }
    @Override
    public boolean isCellEditable(int row, int col) {
        return true;
    }
    
    public void setValueAt(Object value, int row, int col) {
        if (DEBUG) {
          System.out.println("Setting value at " + row + "," + col
              + " to " + value + " (an instance of "
              + value.getClass() + ")");
        }
        data.get(row).set(col, value);
        fireTableCellUpdated(row, col);

        if (DEBUG) {
          System.out.println("New value of data:");
        }
        
      }
    
    public void saveToCSV(String filePath) throws IOException {
        if (data == null || data.size() == 0) {
            return;
        }
        BufferedWriter bw = Files.newWriter(new File(filePath), Charset.forName("UTF-8"));
        bw.write(BookTags.BOOK_TAG_START + "\n");
        for (Vector<Object> datum : data) {
            Iterator<Object> it = datum.iterator();
            String term = "";
            String contents = "";
            String tags = "";
            String misc = "";
            for (int i = 0; it.hasNext(); i++) {
                switch (i) {
                case 0:
                    term = it.next().toString();
                    break;
                case 1:
                    contents = it.next().toString();
                    break;
                case 2:
                    tags = it.next().toString();
                    break;
                case 3: 
                    misc = it.next().toString();
                    break;
                }       
            }
            if (term.length() < 2 && contents.length() < 2 
                    && tags.length() < 2 && misc.length() < 2) {
                continue;
            }
            bw.write(BookTags.NOTE_TAG_START);
            bw.write(BookTags.TERMS_TAG_START);
            bw.write(SpecialChars.regularize(term));
            bw.write(BookTags.TERMS_TAG_END);
            bw.write(BookTags.CONTENTS_TAG_START);
            bw.write(SpecialChars.regularize(contents));
            bw.write(BookTags.CONTENTS_TAG_END);
            bw.write(BookTags.TAGS_TAG_START);
            bw.write(tags);
            bw.write(BookTags.TAGS_TAG_END);
            bw.write(BookTags.MISC_TAG_START);
            bw.write(SpecialChars.regularize(misc));
            bw.write(BookTags.MISC_TAG_END);
            bw.write(BookTags.NOTE_TAG_END);
        }
        bw.write(BookTags.BOOK_TAG_END);
        Closeables.closeQuietly(bw);
    }
    
    public void loadCSV(String filePath) {
        this.modelFilePath = filePath;
        loader = new BookNoteLoader(modelFilePath);
        loader.load();
        List<BookNoteRecord> noteList = loader.getNoteList();
        data.clear();
        highestCellIndex.clear();
        for (BookNoteRecord note : noteList) {
            Vector<Object> datum = new Vector<Object>();
            datum.add(note.getTerm());
            datum.add(note.getContents());
            datum.add(note.getTags());
            datum.add(note.getMisc());
            data.add(datum);
            highestCellIndex.add(0);
        }
        int blankLines = 0;
        if (noteList.size() < 50) {
            blankLines = 50 - noteList.size();
        } else {
            blankLines = 10;
        }

        for (int i = 0; i < blankLines; i++) {
            Vector<Object> datum = new Vector<Object>();
            datum.add("");
            datum.add("");
            datum.add("");
            datum.add("");
            data.add(datum);
            highestCellIndex.add(0);
        }

    }
   public void addRow(Vector<Object> rowData, int row) { 
       this.data.insertElementAt(rowData, row);
       highestCellIndex.insertElementAt(0, row);
       fireTableRowsInserted(row, row);
   }
   
   public void deleteRow(int row) {
       this.data.remove(row);
       highestCellIndex.remove(row);
       fireTableRowsDeleted(row, row+1);
   }
   
   public int getHighestCell(int row) {
       return highestCellIndex.get(row);
   }
   
   public void setHighestCell(int row, int cell){
       highestCellIndex.set(row, cell);
   }
   
   public String getPath() {
       return modelFilePath;
   }

}
